package com.example.util;

import java.util.Date;

import redis.clients.jedis.Jedis;

/**redis 锁实现
 * @author Administrator
 *
 */
public class RedisLockUtiles {
	/*相关说明
	 * 原则上 LIVE_TIME 应当大于FAILURE_TIME ，不然FAILURE_TIME 不会生效
	 * 
	 * */
	
	
	/**锁失效时间,单位（毫秒）默认为-1 表示永不失效 ，从获得锁开始计时，超过该时间后，该锁可被其他线程获取*/
	private static Long FAILURE_TIME = -1L;
	/**锁存在时间,单位（毫秒）默认为-1 表示永不清除 ，超过该时间段后，redis将移除该锁*/
	private static Long LIVE_TIME=-1L;
	private static RedisLockUtiles utils;
	private Jedis client;
	private final String LOCK_PREFIX="redis_lock_";
	private RedisLockUtiles(Jedis client)
	{
		this.client=client;
	}
	
	
	public static synchronized RedisLockUtiles getInstance(Jedis client)
	{
		if(utils==null)
		{
			utils=new RedisLockUtiles(client);
		}
		return utils;
	}
	
	
	/** 
	* 获取redis分布式锁实例，
	* failureTime 原则上应当大于 livetime
	* 
	* @param client  jedis 连接
	* @param failureTime 分布式锁失效时间（单位毫秒）
	* @param liveTime  锁在redis中的livetime（单位毫秒）
	* @return RedisLockUtiles
	* @author liuhuaqing
	* @date 2018年9月3日下午2:39:01
	*/ 
	public static synchronized RedisLockUtiles getInstance(Jedis client,Long failureTime,Long liveTime)
	{
		if(failureTime!=null)
		{
			FAILURE_TIME=failureTime;
		}
		if(liveTime!=null)
		{
			LIVE_TIME=liveTime;
		}
		if(utils==null)
		{
			utils=new RedisLockUtiles(client);
		}
		return utils;
	}
	
	/** 
	*  阻塞式获取指定数据的lock，一直到获取到该锁为止（采用无限循环方式，用于特殊情况-锁定时间非常短）
	*  该方法只有FAILURE_TIME<5*1000(5秒) 内才可使用，否则会抛出 "不可使用" 异常
	* @param key   该类型数据的唯一标识
	* @return Boolean
	* @author liuhuaqing
	* @date 2018年7月5日下午6:07:02
	*/ 
	public Boolean lockByBolck(String key)
	{
	   if(FAILURE_TIME>5*1000||FAILURE_TIME<0)
		{
			throw new RuntimeException("lockByBolck不可使用，F失效时间（AILURE_TIME）必须小于5秒");
		}
	   
	   while(client.setnx(getKey(key),String.valueOf(System.currentTimeMillis())) == 0){
		    Long lockTime = Long.valueOf(client.get(getKey(key)));
	        if (lockTime!=null && System.currentTimeMillis() > lockTime+FAILURE_TIME) {
	            client.del(getKey(key));
	        }
	   }
	   
	   return true;
	}
	
	
	/** 
	* 尝试获取锁，锁定成功返回true，失败返回false
	* @param key
	* @return Boolean
	* @author liuhuaqing
	* @date 2018年8月31日下午2:10:10
	*/ 
	public Boolean lockByTry(String key)
	{
		if(FAILURE_TIME>0)
		{
			Long lockTime;
			if(client.get(getKey(key))==null)
			{
				lockTime=new Date().getTime();
			}else
			{
				lockTime = Long.valueOf(client.get(getKey(key)));
			}
	        if (lockTime!=null && System.currentTimeMillis() > lockTime+FAILURE_TIME) {
	            client.del(getKey(key));
	        }
		}
		
		if(client.setnx(getKey(key),String.valueOf(System.currentTimeMillis())) == 0)
		{
			return false;
		}else
		{
			return true;
		}
	  
	}
	
	
	
	/** 
	* 解锁
	* @param key void
	* @author liuhuaqing
	* @date 2018年7月5日下午6:12:26
	*/ 
	public  void unLock(String key)
	{
		 client.del(getKey(key));
	}
	
	
	private String getKey(String id)
	{
		return LOCK_PREFIX+id;
	}
}
